using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;

namespace Countdown
{
    public class Countdowner
    {
        private Dictionary<TimeSpan, Action<TimeSpan>> _timedActions;
        private Action _onComplete;
        private Timer _updateTimer;
        private Timer _totalTimer;
        private DateTime _startTime;
        private TimeSpan _length;

        public Countdowner( DateTime destination, Action<TimeSpan> updateAction, Action onComplete, Dictionary<TimeSpan, Action<TimeSpan>> timedActions )
            : this( destination - DateTime.Now, updateAction, onComplete, timedActions )
        {
        }

        public Countdowner( TimeSpan length, Action<TimeSpan> updateAction, Action onComplete, Dictionary<TimeSpan, Action<TimeSpan>> timedActions )
        {
            _onComplete = onComplete;
            _timedActions = timedActions;

            _length = length;

            _updateTimer = new Timer( 1 * 1000 );
            _totalTimer = new Timer( length.TotalMilliseconds );


            _updateTimer.Elapsed += ( o, e ) =>
            {
                var timeLeft = (_length - (DateTime.Now - _startTime));

                Dispatch( () => updateAction( timeLeft ) );
                foreach ( var pair in _timedActions )
                    if ( (int)Math.Round( (pair.Key - timeLeft).TotalSeconds, 0 ) == 0 )
                        Dispatch( () => pair.Value( timeLeft ) );
            };

            _totalTimer.Elapsed += ( o, e ) =>
            {
                Stop();
                Dispatch( () => updateAction( new TimeSpan( 0 ) ) );
                Dispatch( () => _onComplete() );
            };
        }

        public void Start()
        {
            _startTime = DateTime.Now;
            _totalTimer.Start();
            _updateTimer.Start();
        }

        public void Stop()
        {
            _totalTimer.Stop();
            _updateTimer.Stop();
        }

        public void Dispatch( Action action )
        {
            Application.Current.Dispatcher.Invoke( action, new object[] { } );
        }
    }
}